package gui;

import fn.Function;
import inter.Interpolation;
import inter.Lagrange;
import inter.NewtonDividedDifference;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.DefaultComboBoxModel;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTable;
import javax.swing.JTextPane;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.ScrollPaneConstants;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;

public class InterpolationPanel extends JPanel {
	private static final long serialVersionUID = -4365895485136203131L;

	private JLabel label;
	private JSeparator separator;
	private JComboBox<Interpolation> comboBox;
	public JLabel lblNodes;
	public JSeparator separator_2;
	public JScrollPane scrollPane_1;
	public JTable table;
	public JButton btnAdd;
	public JButton btnRemove;
	private PlotCanvas plot;
	public JLabel lblFunction;
	public JSeparator separator_1;
	public JTextPane txtpnInterfn;
	public JCheckBox chckbxF;

	public static void main(String[] args) throws Exception {
		UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		JFrame f = new JFrame();
		f.setVisible(true);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		InterpolationPanel p = new InterpolationPanel(null);
		f.getContentPane().add(p);
		f.pack();
	}

	public InterpolationPanel(PlotCanvas p) {
		this.plot = p;
		init();
	}

	private void init() {
		setPreferredSize(new Dimension(256, 256));
		comboBox = new JComboBox<Interpolation>();
		comboBox.setModel(new DefaultComboBoxModel<Interpolation>(new Interpolation[] { new Lagrange(), new NewtonDividedDifference() }));
		label = new JLabel("Method");
		separator = new JSeparator();
		lblNodes = new JLabel("Nodes");
		separator_2 = new JSeparator();
		scrollPane_1 = new JScrollPane();
		scrollPane_1.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

		btnAdd = new JButton("+");
		btnAdd.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				do_btnAdd_actionPerformed(arg0);
			}
		});

		btnRemove = new JButton("-");
		btnRemove.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				do_btnRemove_actionPerformed(e);
			}
		});

		lblFunction = new JLabel("Function");

		separator_1 = new JSeparator();

		txtpnInterfn = new JTextPane();
		txtpnInterfn.setEnabled(false);
		txtpnInterfn.setBorder(UIManager.getBorder("ScrollPane.border"));

		chckbxF = new JCheckBox("Use");
		chckbxF.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				do_chckbxF_actionPerformed(arg0);
			}
		});
		GroupLayout groupLayout = new GroupLayout(this);
		groupLayout.setHorizontalGroup(
			groupLayout.createParallelGroup(Alignment.LEADING)
				.addGroup(groupLayout.createSequentialGroup()
					.addContainerGap()
					.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
						.addGroup(Alignment.TRAILING, groupLayout.createSequentialGroup()
							.addComponent(label, GroupLayout.PREFERRED_SIZE, 59, GroupLayout.PREFERRED_SIZE)
							.addGap(5)
							.addComponent(separator, GroupLayout.PREFERRED_SIZE, 172, Short.MAX_VALUE))
						.addComponent(comboBox, Alignment.TRAILING, 0, 236, Short.MAX_VALUE)
						.addGroup(Alignment.TRAILING, groupLayout.createSequentialGroup()
							.addComponent(lblFunction, GroupLayout.PREFERRED_SIZE, 59, GroupLayout.PREFERRED_SIZE)
							.addGap(5)
							.addComponent(separator_1, GroupLayout.DEFAULT_SIZE, 172, Short.MAX_VALUE))
						.addGroup(groupLayout.createSequentialGroup()
							.addGap(1)
							.addComponent(chckbxF)
							.addPreferredGap(ComponentPlacement.RELATED)
							.addComponent(txtpnInterfn, GroupLayout.DEFAULT_SIZE, 190, Short.MAX_VALUE))
						.addComponent(scrollPane_1, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 236, Short.MAX_VALUE)
						.addGroup(Alignment.TRAILING, groupLayout.createSequentialGroup()
							.addComponent(btnRemove)
							.addPreferredGap(ComponentPlacement.RELATED)
							.addComponent(btnAdd))
						.addGroup(Alignment.TRAILING, groupLayout.createSequentialGroup()
							.addComponent(lblNodes, GroupLayout.PREFERRED_SIZE, 59, GroupLayout.PREFERRED_SIZE)
							.addGap(5)
							.addComponent(separator_2, GroupLayout.PREFERRED_SIZE, 172, Short.MAX_VALUE)))
					.addContainerGap())
		);
		groupLayout.setVerticalGroup(
			groupLayout.createParallelGroup(Alignment.LEADING)
				.addGroup(groupLayout.createSequentialGroup()
					.addContainerGap()
					.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
						.addComponent(label, GroupLayout.PREFERRED_SIZE, 16, GroupLayout.PREFERRED_SIZE)
						.addGroup(groupLayout.createSequentialGroup()
							.addGap(12)
							.addComponent(separator, GroupLayout.PREFERRED_SIZE, 4, GroupLayout.PREFERRED_SIZE)))
					.addGap(7)
					.addComponent(comboBox, GroupLayout.PREFERRED_SIZE, 23, GroupLayout.PREFERRED_SIZE)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
						.addComponent(separator_1, GroupLayout.PREFERRED_SIZE, 4, GroupLayout.PREFERRED_SIZE)
						.addComponent(lblFunction, GroupLayout.PREFERRED_SIZE, 16, GroupLayout.PREFERRED_SIZE))
					.addPreferredGap(ComponentPlacement.RELATED)
					.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
						.addComponent(chckbxF)
						.addComponent(txtpnInterfn, GroupLayout.PREFERRED_SIZE, 31, GroupLayout.PREFERRED_SIZE))
					.addPreferredGap(ComponentPlacement.RELATED)
					.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
						.addComponent(lblNodes, GroupLayout.PREFERRED_SIZE, 16, GroupLayout.PREFERRED_SIZE)
						.addGroup(groupLayout.createSequentialGroup()
							.addGap(12)
							.addComponent(separator_2, GroupLayout.PREFERRED_SIZE, 4, GroupLayout.PREFERRED_SIZE)))
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(scrollPane_1, GroupLayout.PREFERRED_SIZE, 72, GroupLayout.PREFERRED_SIZE)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
						.addComponent(btnRemove)
						.addComponent(btnAdd))
					.addContainerGap())
		);

		table = new JTable() {
			private static final long serialVersionUID = 3921483845721523529L;

			@Override
			public void setValueAt(Object paramObject, int paramInt1, int paramInt2) {
				super.setValueAt(paramObject, paramInt1, paramInt2);
				refreshNodes();
			}

			@Override
			public Object getValueAt(int paramInt1, int paramInt2) {
				return super.getValueAt(paramInt1, paramInt2) + "";
			}
		};
		table.setModel(new DefaultTableModel(new Object[][] { { "0", "1", "1" }, { "1", "2", "2" }, { "2", "3", "0" }, }, new String[] { "", "x", "f(x)" }) {
			private static final long serialVersionUID = 3409522548249898554L;
			boolean[] columnEditables = new boolean[] { false, true, true };

			public boolean isCellEditable(int row, int column) {
				return columnEditables[column];
			}
		});
		table.getColumnModel().getColumn(0).setResizable(false);
		table.getColumnModel().getColumn(0).setPreferredWidth(40);
		table.getColumnModel().getColumn(1).setResizable(false);
		table.getColumnModel().getColumn(2).setResizable(false);
		scrollPane_1.setViewportView(table);
		setLayout(groupLayout);
	}

	protected void do_btnAdd_actionPerformed(ActionEvent arg0) {
		((DefaultTableModel) table.getModel()).addRow(new String[] { table.getModel().getRowCount() + "", "0", "0" });
		refreshNodes();
	}

	protected void do_btnRemove_actionPerformed(ActionEvent e) {
		int start = table.getSelectedRow();
		if (table.getModel().getRowCount() > 1 && start >= 0 && start < table.getRowCount())
			((DefaultTableModel) table.getModel()).removeRow(table.getSelectedRow());
		if (start >= 0)
			for (int i = start; i < table.getRowCount(); i++)
				if (table.getValueAt(i, 0) instanceof String)
					table.setValueAt(Integer.parseInt((String) table.getValueAt(i, 0)) - 1, i, 0);
				else if (table.getValueAt(i, 0) instanceof Integer)
					table.setValueAt(((Integer) table.getValueAt(i, 0)) - 1, i, 0);
				else
					System.out.println(i + " " + table.getValueAt(i, 0));
		refreshNodes();
	}

	public Function solve() {
		return ((Interpolation) comboBox.getSelectedItem()).solve(getNodes());
	}

	public Function error() {
		if (!chckbxF.isSelected())
			return null;
		return ((Interpolation) comboBox.getSelectedItem()).getError(getNodes(), Function.parse(txtpnInterfn.getText()));
	}

	private double[][] getNodes() {
		double[][] nodes = new double[table.getRowCount()][table.getColumnCount() - 1];
		if (!chckbxF.isSelected()) {
			for (int i = 0; i < nodes.length; i++)
				for (int j = 0; j < nodes[i].length; j++)
					nodes[i][j] = Double.parseDouble((String) table.getValueAt(i, j + 1));
		} else {
			Function fn = Function.parse(txtpnInterfn.getText());
			for (int i = 0; i < nodes.length; i++) {
				nodes[i][0] = Double.parseDouble((String) table.getValueAt(i, 1));
				nodes[i][1] = fn.evaluate(nodes[i][0]);
				table.setValueAt(nodes[i][1], i, 2);
			}
		}
		refreshNodes();
		return nodes;
	}

	public void refreshNodes() {
		if (plot != null) {
			plot.removePointAll();
			for (int y = 0; y < table.getRowCount(); y++) {
				double x = Double.parseDouble((String) table.getValueAt(y, 1));
				double fx = Double.parseDouble((String) table.getValueAt(y, 2));
				plot.addPoint(new Point(x, fx), PlotCanvas.TYPE_NONE);
			}
		}
	}

	protected void do_chckbxF_actionPerformed(ActionEvent arg0) {
		txtpnInterfn.setEnabled(chckbxF.isSelected());
	}

	public Function originalFn() {
		if (!chckbxF.isSelected())
			return null;
		try {
			return Function.parse(txtpnInterfn.getText());
		} catch (Exception e) {}
		return null;
	}
}
